﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using xxpl1.Utils;

namespace xxpl1.HTTP.Parser
{
    public class HttpResponse
    {
        private readonly List<string> cookies = new List<string>();
        private readonly List<HttpHeader> headers = new List<HttpHeader>();
        private readonly Stream clientStream;
        private bool headerRendered;
        private bool canCache;

        private MemoryStream cacheStream;
        private DateTime? expires;

        public HttpResponse(Stream clientStream)
        {
            this.clientStream = clientStream;
        }

        public int Status { get; set; }

        public int ContentLength { get; set; }

        public bool IsFromCache { get; set; }

        public bool CanCache
        {
            get { return canCache; }
        }

        public DateTime Exipre
        {
            get { return expires.GetValueOrDefault(); }
        }

        public void AddCookie(string cookie)
        {
            cookies.Add(cookie);
        }

        public void AddHeader(string header, string value)
        {
            if ("expires".Equals(header, StringComparison.OrdinalIgnoreCase))
            {
                DateTime temp;
                if (DateTime.TryParse(value, out temp))
                {
                    expires = temp.ToUniversalTime();
                }
            }
            else if ("cache-control".Equals(header, StringComparison.OrdinalIgnoreCase))
            {
                expires = Guard.ParseCacheControl(value);
            }
            headers.Add(new HttpHeader(header, value));
        }

        public void Write(byte[] content, int start, int length)
        {
            if (!headerRendered)
            {
                canCache = Settings.Instance.EnableCache
                           && Status == 200
                           && cookies.Count == 0
                           && expires > DateTime.UtcNow.AddMinutes(10);

                RenderHeader(clientStream, false);
            }

            if (canCache)
            {
                if (cacheStream == null) cacheStream = new MemoryStream();
                cacheStream.Write(content, start, length);
            }

            clientStream.Write(content, start, length);
        }

        public void SendCache(byte[] content)
        {
            clientStream.Write(content, 0, content.Length);
        }

        public void Abort()
        {
            clientStream.Write(Resources.Instance.Http500Bytes, 0, Resources.Instance.Http500Bytes.Length);
        }

        public void Close()
        {
            if (!headerRendered)
            {
                RenderHeader(clientStream, false);
            }

            clientStream.Flush();
        }

        private void RenderHeader(Stream stream, bool fromCache)
        {
            var sb = new StringBuilder();
            sb.AppendFormat("HTTP/1.1 {0} OK\r\n", Status);
            foreach (HttpHeader httpHeader in headers)
            {
                sb.AppendFormat("{0}: {1}\r\n", httpHeader.Name, httpHeader.Value);
            }
            foreach (string cooky in cookies)
            {
                sb.AppendFormat("{0}: {1}\r\n", "set-cookie", cooky);
            }
            sb.AppendFormat("{0}: {1}\r\n", "content-length", ContentLength);
            if (fromCache)
                sb.AppendFormat("X-CA: 200 Hit from Memory Cache\r\n");
            sb.AppendFormat("\r\n");
            byte[] content = Encoding.ASCII.GetBytes(sb.ToString());
            stream.Write(content, 0, content.Length);
            headerRendered = true;
        }

        public void RenderToCacheStream(MemoryStream ms)
        {
            RenderHeader(ms, true);
            cacheStream.WriteTo(ms);
        }

        public void Send304()
        {
            clientStream.Write(Resources.Instance.Http304Bytes, 0, Resources.Instance.Http304Bytes.Length);
        }
    }
}